1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package sun.awt.X11;
32
33 import sun.misc.Unsafe;
34 import java.awt.Insets;
35 import java.awt.Frame;
36 import java.awt.Rectangle;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.LinkedList;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42 import sun.util.logging.PlatformLogger;
43
44
45
46
47
48
49 final class XWM
50 {
51
52 private final static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWM");
53 private final static PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XWM");
54 private final static PlatformLogger stateLog = PlatformLogger.getLogger("sun.awt.X11.states.XWM");
55
56 static final XAtom XA_MWM_HINTS = new XAtom();
57
58 private static Unsafe unsafe = XlibWrapper.unsafe;
59
60
61
62 static XAtom XA_WM_STATE = new XAtom();
63
64
65 XAtom XA_UTF8_STRING = XAtom.get("UTF8_STRING");
66
67
68 final static int AWT_NET_N_KNOWN_STATES=2;
69
70
71 final static XAtom XA_E_FRAME_SIZE = new XAtom();
72
73
74 final static XAtom XA_KDE_NET_WM_FRAME_STRUT = new XAtom();
75
76
77 final static XAtom XA_KWM_WIN_ICONIFIED = new XAtom();
78 final static XAtom XA_KWM_WIN_MAXIMIZED = new XAtom();
79
80
81 final static XAtom XA_OL_DECOR_DEL = new XAtom();
82 final static XAtom XA_OL_DECOR_HEADER = new XAtom();
83 final static XAtom XA_OL_DECOR_RESIZE = new XAtom();
84 final static XAtom XA_OL_DECOR_PIN = new XAtom();
85 final static XAtom XA_OL_DECOR_CLOSE = new XAtom();
86
87
88 final static XAtom XA_NET_FRAME_EXTENTS = new XAtom();
89 final static XAtom XA_NET_REQUEST_FRAME_EXTENTS = new XAtom();
90
91 final static int
92 UNDETERMINED_WM = 1,
93 NO_WM = 2,
94 OTHER_WM = 3,
95 OPENLOOK_WM = 4,
96 MOTIF_WM = 5,
97 CDE_WM = 6,
98 ENLIGHTEN_WM = 7,
99 KDE2_WM = 8,
100 SAWFISH_WM = 9,
101 ICE_WM = 10,
102 METACITY_WM = 11,
103 COMPIZ_WM = 12,
104 LG3D_WM = 13;
105 public String toString() {
106 switch (WMID) {
107 case NO_WM:
108 return "NO WM";
109 case OTHER_WM:
110 return "Other WM";
111 case OPENLOOK_WM:
112 return "OPENLOOK";
113 case MOTIF_WM:
114 return "MWM";
115 case CDE_WM:
116 return "DTWM";
117 case ENLIGHTEN_WM:
118 return "Enlightenment";
119 case KDE2_WM:
120 return "KWM2";
121 case SAWFISH_WM:
122 return "Sawfish";
123 case ICE_WM:
124 return "IceWM";
125 case METACITY_WM:
126 return "Metacity";
127 case COMPIZ_WM:
128 return "Compiz";
129 case LG3D_WM:
130 return "LookingGlass";
131 case UNDETERMINED_WM:
132 default:
133 return "Undetermined WM";
134 }
135 }
136
137
138 int WMID;
139 static final Insets zeroInsets = new Insets(0, 0, 0, 0);
140 static final Insets defaultInsets = new Insets(25, 5, 5, 5);
141
142 XWM(int WMID) {
143 this.WMID = WMID;
144 initializeProtocols();
145 if (log.isLoggable(PlatformLogger.FINE)) log.fine("Window manager: " + toString());
146 }
147 int getID() {
148 return WMID;
149 }
150
151
152 static Insets normalize(Insets insets) {
153 if (insets.top > 64 || insets.top < 0) {
154 insets.top = 28;
155 }
156 if (insets.left > 32 || insets.left < 0) {
157 insets.left = 6;
158 }
159 if (insets.right > 32 || insets.right < 0) {
160 insets.right = 6;
161 }
162 if (insets.bottom > 32 || insets.bottom < 0) {
163 insets.bottom = 6;
164 }
165 return insets;
166 }
167
168 static XNETProtocol g_net_protocol = null;
169 static XWINProtocol g_win_protocol = null;
170 static boolean isNetWMName(String name) {
171 if (g_net_protocol != null) {
172 return g_net_protocol.isWMName(name);
173 } else {
174 return false;
175 }
176 }
177
178 static void initAtoms() {
179 final Object[][] atomInitList ={
180 { XA_WM_STATE, "WM_STATE" },
181
182 { XA_KDE_NET_WM_FRAME_STRUT, "_KDE_NET_WM_FRAME_STRUT" },
183
184 { XA_E_FRAME_SIZE, "_E_FRAME_SIZE" },
185
186 { XA_KWM_WIN_ICONIFIED, "KWM_WIN_ICONIFIED" },
187 { XA_KWM_WIN_MAXIMIZED, "KWM_WIN_MAXIMIZED" },
188
189 { XA_OL_DECOR_DEL, "_OL_DECOR_DEL" },
190 { XA_OL_DECOR_HEADER, "_OL_DECOR_HEADER" },
191 { XA_OL_DECOR_RESIZE, "_OL_DECOR_RESIZE" },
192 { XA_OL_DECOR_PIN, "_OL_DECOR_PIN" },
193 { XA_OL_DECOR_CLOSE, "_OL_DECOR_CLOSE" },
194 { XA_MWM_HINTS, "_MOTIF_WM_HINTS" },
195 { XA_NET_FRAME_EXTENTS, "_NET_FRAME_EXTENTS" },
196 { XA_NET_REQUEST_FRAME_EXTENTS, "_NET_REQUEST_FRAME_EXTENTS" },
197 };
198
199 String[] names = new String[atomInitList.length];
200 for (int index = 0; index < names.length; index++) {
201 names[index] = (String)atomInitList[index][1];
202 }
203
204 int atomSize = XAtom.getAtomSize();
205 long atoms = unsafe.allocateMemory(names.length*atomSize);
206 XToolkit.awtLock();
207 try {
208 int status = XlibWrapper.XInternAtoms(XToolkit.getDisplay(), names, false, atoms);
209 if (status == 0) {
210 return;
211 }
212 for (int atom = 0, atomPtr = 0; atom < names.length; atom++, atomPtr += atomSize) {
213 ((XAtom)(atomInitList[atom][0])).setValues(XToolkit.getDisplay(), names[atom], XAtom.getAtom(atoms + atomPtr));
214 }
215 } finally {
216 XToolkit.awtUnlock();
217 unsafe.freeMemory(atoms);
218 }
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 private static boolean isNoWM() {
239
240
241
242 String vendor_string = XlibWrapper.ServerVendor(XToolkit.getDisplay());
243 if (vendor_string.indexOf("eXcursion") != -1) {
244
245
246
247
248
249 if (insLog.isLoggable(PlatformLogger.FINE)) {
250 insLog.finer("eXcursion means NO_WM");
251 }
252 return true;
253 }
254
255 XSetWindowAttributes substruct = new XSetWindowAttributes();
256 try {
257
258
259
260 final long default_screen_number =
261 XlibWrapper.DefaultScreen(XToolkit.getDisplay());
262 final String selection_name = "WM_S" + default_screen_number;
263
264 long selection_owner =
265 XlibWrapper.XGetSelectionOwner(XToolkit.getDisplay(),
266 XAtom.get(selection_name).getAtom());
267 if (insLog.isLoggable(PlatformLogger.FINE)) {
268 insLog.finer("selection owner of " + selection_name
269 + " is " + selection_owner);
270 }
271
272 if (selection_owner != XConstants.None) {
273 return false;
274 }
275
276 winmgr_running = false;
277 substruct.set_event_mask(XConstants.SubstructureRedirectMask);
278
279 XToolkit.WITH_XERROR_HANDLER(detectWMHandler);
280 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
281 XToolkit.getDefaultRootWindow(),
282 XConstants.CWEventMask,
283 substruct.pData);
284 XToolkit.RESTORE_XERROR_HANDLER();
285
286
287
288
289
290 if (!winmgr_running) {
291 substruct.set_event_mask(0);
292 XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),
293 XToolkit.getDefaultRootWindow(),
294 XConstants.CWEventMask,
295 substruct.pData);
296 if (insLog.isLoggable(PlatformLogger.FINE)) {
297 insLog.finer("It looks like there is no WM thus NO_WM");
298 }
299 }
300
301 return !winmgr_running;
302 } finally {
303 substruct.dispose();
304 }
305 }
306
307 static XAtom XA_ENLIGHTENMENT_COMMS = new XAtom("ENLIGHTENMENT_COMMS", false);
308
309
310
311
312
313
314 static long getECommsWindowIDProperty(long window) {
315
316 if (!XA_ENLIGHTENMENT_COMMS.isInterned()) {
317 return 0;
318 }
319
320 WindowPropertyGetter getter =
321 new WindowPropertyGetter(window, XA_ENLIGHTENMENT_COMMS, 0, 14, false,
322 XAtom.XA_STRING);
323 try {
324 int status = getter.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
325 if (status != XConstants.Success || getter.getData() == 0) {
326 return 0;
327 }
328
329 if (getter.getActualType() != XAtom.XA_STRING
330 || getter.getActualFormat() != 8
331 || getter.getNumberOfItems() != 14 || getter.getBytesAfter() != 0)
332 {
333 return 0;
334 }
335
336
337 byte[] bytes = XlibWrapper.getStringBytes(getter.getData());
338 String id = new String(bytes);
339
340 log.finer("ENLIGHTENMENT_COMMS is " + id);
341
342
343 Pattern winIdPat = Pattern.compile("WINID\\s+(\\p{XDigit}{0,8})");
344 try {
345 Matcher match = winIdPat.matcher(id);
346 if (match.matches()) {
347 log.finest("Match group count: " + match.groupCount());
348 String longId = match.group(1);
349 log.finest("Match group 1 " + longId);
350 long winid = Long.parseLong(longId, 16);
351 log.finer("Enlightenment communication window " + winid);
352 return winid;
353 } else {
354 log.finer("ENLIGHTENMENT_COMMS has wrong format");
355 return 0;
356 }
357 } catch (Exception e) {
358 if (log.isLoggable(PlatformLogger.FINER)) {
359 e.printStackTrace();
360 }
361 return 0;
362 }
363 } finally {
364 getter.dispose();
365 }
366 }
367
368
369
370
371
372 static boolean isEnlightenment() {
373
374 long root_xref = getECommsWindowIDProperty(XToolkit.getDefaultRootWindow());
375 if (root_xref == 0) {
376 return false;
377 }
378
379 long self_xref = getECommsWindowIDProperty(root_xref);
380 if (self_xref != root_xref) {
381 return false;
382 }
383
384 return true;
385 }
386
387
388
389
390
391
392
393
394
395
396
397
398
399 static final XAtom XA_DT_SM_WINDOW_INFO = new XAtom("_DT_SM_WINDOW_INFO", false);
400 static final XAtom XA_DT_SM_STATE_INFO = new XAtom("_DT_SM_STATE_INFO", false);
401 static boolean isCDE() {
402
403 if (!XA_DT_SM_WINDOW_INFO.isInterned()) {
404 log.finer("{0} is not interned", XA_DT_SM_WINDOW_INFO);
405 return false;
406 }
407
408 WindowPropertyGetter getter =
409 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
410 XA_DT_SM_WINDOW_INFO, 0, 2,
411 false, XA_DT_SM_WINDOW_INFO);
412 try {
413 int status = getter.execute();
414 if (status != XConstants.Success || getter.getData() == 0) {
415 log.finer("Getting of _DT_SM_WINDOW_INFO is not successfull");
416 return false;
417 }
418 if (getter.getActualType() != XA_DT_SM_WINDOW_INFO.getAtom()
419 || getter.getActualFormat() != 32
420 || getter.getNumberOfItems() != 2 || getter.getBytesAfter() != 0)
421 {
422 log.finer("Wrong format of _DT_SM_WINDOW_INFO");
423 return false;
424 }
425
426 long wmwin = Native.getWindow(getter.getData(), 1);
427
428 if (wmwin == 0) {
429 log.fine("WARNING: DT_SM_WINDOW_INFO exists but returns zero windows");
430 return false;
431 }
432
433
434 if (!XA_DT_SM_STATE_INFO.isInterned()) {
435 log.finer("{0} is not interned", XA_DT_SM_STATE_INFO);
436 return false;
437 }
438 WindowPropertyGetter getter2 =
439 new WindowPropertyGetter(wmwin, XA_DT_SM_STATE_INFO, 0, 1,
440 false, XA_DT_SM_STATE_INFO);
441 try {
442 status = getter2.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
443
444
445 if (status != XConstants.Success || getter2.getData() == 0) {
446 log.finer("Getting of _DT_SM_STATE_INFO is not successfull");
447 return false;
448 }
449 if (getter2.getActualType() != XA_DT_SM_STATE_INFO.getAtom()
450 || getter2.getActualFormat() != 32)
451 {
452 log.finer("Wrong format of _DT_SM_STATE_INFO");
453 return false;
454 }
455
456 return true;
457 } finally {
458 getter2.dispose();
459 }
460 } finally {
461 getter.dispose();
462 }
463 }
464
465
466
467
468
469
470
471
472 static final XAtom XA_MOTIF_WM_INFO = new XAtom("_MOTIF_WM_INFO", false);
473 static final XAtom XA_DT_WORKSPACE_CURRENT = new XAtom("_DT_WORKSPACE_CURRENT", false);
474 static boolean isMotif() {
475
476 if (!(XA_MOTIF_WM_INFO.isInterned()) ) {
477 return false;
478 }
479
480 WindowPropertyGetter getter =
481 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
482 XA_MOTIF_WM_INFO, 0,
483 MWMConstants.PROP_MOTIF_WM_INFO_ELEMENTS,
484 false, XA_MOTIF_WM_INFO);
485 try {
486 int status = getter.execute();
487
488 if (status != XConstants.Success || getter.getData() == 0) {
489 return false;
490 }
491
492 if (getter.getActualType() != XA_MOTIF_WM_INFO.getAtom()
493 || getter.getActualFormat() != 32
494 || getter.getNumberOfItems() != MWMConstants.PROP_MOTIF_WM_INFO_ELEMENTS
495 || getter.getBytesAfter() != 0)
496 {
497 return false;
498 }
499
500 long wmwin = Native.getLong(getter.getData(), 1);
501 if (wmwin != 0) {
502 if (XA_DT_WORKSPACE_CURRENT.isInterned()) {
503
504 XAtom[] curws = XA_DT_WORKSPACE_CURRENT.getAtomListProperty(wmwin);
505 if (curws.length == 0) {
506 return false;
507 }
508 return true;
509 } else {
510
511
512
513 WindowPropertyGetter state_getter =
514 new WindowPropertyGetter(wmwin,
515 XA_WM_STATE,
516 0, 1, false,
517 XA_WM_STATE);
518 try {
519 if (state_getter.execute() == XConstants.Success &&
520 state_getter.getData() != 0 &&
521 state_getter.getActualType() == XA_WM_STATE.getAtom())
522 {
523 return true;
524 }
525 } finally {
526 state_getter.dispose();
527 }
528 }
529 }
530 } finally {
531 getter.dispose();
532 }
533 return false;
534 }
535
536
537
538
539 static boolean isSawfish() {
540 return isNetWMName("Sawfish");
541 }
542
543
544
545
546 static boolean isKDE2() {
547 return isNetWMName("KWin");
548 }
549
550 static boolean isCompiz() {
551 return isNetWMName("compiz");
552 }
553
554 static boolean isLookingGlass() {
555 return isNetWMName("LG3D");
556 }
557
558
559
560
561 static boolean isMetacity() {
562 return isNetWMName("Metacity");
563
564
565
566
567 }
568
569 static boolean isNonReparentingWM() {
570 return (XWM.getWMID() == XWM.COMPIZ_WM || XWM.getWMID() == XWM.LG3D_WM);
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 static final XAtom XA_ICEWM_WINOPTHINT = new XAtom("_ICEWM_WINOPTHINT", false);
587 static final char opt[] = {
588 'A','W','T','_','I','C','E','W','M','_','T','E','S','T','\0',
589 'a','l','l','W','o','r','k','s','p','a','c','e','s','\0',
590 '0','\0'
591 };
592 static boolean prepareIsIceWM() {
593
594
595
596
597
598 if (!XA_ICEWM_WINOPTHINT.isInterned()) {
599 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
600 return false;
601 }
602
603 XToolkit.awtLock();
604 try {
605 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
606 XlibWrapper.XChangePropertyS(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
607 XA_ICEWM_WINOPTHINT.getAtom(),
608 XA_ICEWM_WINOPTHINT.getAtom(),
609 8, XConstants.PropModeReplace,
610 new String(opt));
611 XToolkit.RESTORE_XERROR_HANDLER();
612
613 if (XToolkit.saved_error != null && XToolkit.saved_error.get_error_code() != XConstants.Success) {
614 log.finer("Erorr getting XA_ICEWM_WINOPTHINT property");
615 return false;
616 }
617 log.finer("Prepared for IceWM detection");
618 return true;
619 } finally {
620 XToolkit.awtUnlock();
621 }
622 }
623
624
625
626
627
628
629
630 static boolean isIceWM() {
631 if (!XA_ICEWM_WINOPTHINT.isInterned()) {
632 log.finer("{0} is not interned", XA_ICEWM_WINOPTHINT);
633 return false;
634 }
635
636 WindowPropertyGetter getter =
637 new WindowPropertyGetter(XToolkit.getDefaultRootWindow(),
638 XA_ICEWM_WINOPTHINT, 0, 0xFFFF,
639 true, XA_ICEWM_WINOPTHINT);
640 try {
641 int status = getter.execute();
642 boolean res = (status == XConstants.Success && getter.getActualType() != 0);
643 log.finer("Status getting XA_ICEWM_WINOPTHINT: " + !res);
644 return !res || isNetWMName("IceWM");
645 } finally {
646 getter.dispose();
647 }
648 }
649
650
651
652
653
654
655
656 static final XAtom XA_SUN_WM_PROTOCOLS = new XAtom("_SUN_WM_PROTOCOLS", false);
657 static boolean isOpenLook() {
658 if (!XA_SUN_WM_PROTOCOLS.isInterned()) {
659 return false;
660 }
661
662 XAtom[] list = XA_SUN_WM_PROTOCOLS.getAtomListProperty(XToolkit.getDefaultRootWindow());
663 return (list.length != 0);
664 }
665
666
667
668
669
670 private static boolean winmgr_running = false;
671 private static XErrorHandler detectWMHandler = new XErrorHandler.XBaseErrorHandler() {
672 @Override
673 public int handleError(long display, XErrorEvent err) {
674 if ((err.get_request_code() == XProtocolConstants.X_ChangeWindowAttributes) &&
675 (err.get_error_code() == XConstants.BadAccess))
676 {
677 winmgr_running = true;
678 return 0;
679 }
680 return super.handleError(display, err);
681 }
682 };
683
684
685
686
687
688 static int awt_wmgr = XWM.UNDETERMINED_WM;
689 static XWM wm;
690 static XWM getWM() {
691 if (wm == null) {
692 wm = new XWM(awt_wmgr = getWMID());
693 }
694 return wm;
695 }
696 static int getWMID() {
697 if (insLog.isLoggable(PlatformLogger.FINEST)) {
698 insLog.finest("awt_wmgr = " + awt_wmgr);
699 }
700
701
702
703
704
705 if (awt_wmgr != XWM.UNDETERMINED_WM) {
706 return awt_wmgr;
707 }
708
709 XSetWindowAttributes substruct = new XSetWindowAttributes();
710 XToolkit.awtLock();
711 try {
712 if (isNoWM()) {
713 awt_wmgr = XWM.NO_WM;
714 return awt_wmgr;
715 }
716
717
718
719 XNETProtocol l_net_protocol = g_net_protocol = new XNETProtocol();
720 l_net_protocol.detect();
721 if (log.isLoggable(PlatformLogger.FINE) && l_net_protocol.active()) {
722 log.fine("_NET_WM_NAME is " + l_net_protocol.getWMName());
723 }
724 XWINProtocol win = g_win_protocol = new XWINProtocol();
725 win.detect();
726
727
728 boolean doIsIceWM = prepareIsIceWM();
729
730
731
732
733
734 if (isEnlightenment()) {
735 awt_wmgr = XWM.ENLIGHTEN_WM;
736 } else if (isMetacity()) {
737 awt_wmgr = XWM.METACITY_WM;
738 } else if (isSawfish()) {
739 awt_wmgr = XWM.SAWFISH_WM;
740 } else if (isKDE2()) {
741 awt_wmgr =XWM.KDE2_WM;
742 } else if (isCompiz()) {
743 awt_wmgr = XWM.COMPIZ_WM;
744 } else if (isLookingGlass()) {
745 awt_wmgr = LG3D_WM;
746 } else if (doIsIceWM && isIceWM()) {
747 awt_wmgr = XWM.ICE_WM;
748 }
749
750
751
752
753 else if (l_net_protocol.active()) {
754 awt_wmgr = XWM.OTHER_WM;
755 } else if (win.active()) {
756 awt_wmgr = XWM.OTHER_WM;
757 }
758
759
760
761 else if (isCDE()) {
762 awt_wmgr = XWM.CDE_WM;
763 } else if (isMotif()) {
764 awt_wmgr = XWM.MOTIF_WM;
765 } else if (isOpenLook()) {
766 awt_wmgr = XWM.OPENLOOK_WM;
767 } else {
768 awt_wmgr = XWM.OTHER_WM;
769 }
770
771 return awt_wmgr;
772 } finally {
773 XToolkit.awtUnlock();
774 substruct.dispose();
775 }
776 }
777
778
779
780
781
782
783
784
785
786
787
788
789
790 static void removeSizeHints(XDecoratedPeer window, long mask) {
791 mask &= XUtilConstants.PMaxSize | XUtilConstants.PMinSize;
792
793 XToolkit.awtLock();
794 try {
795 XSizeHints hints = window.getHints();
796 if ((hints.get_flags() & mask) == 0) {
797 return;
798 }
799
800 hints.set_flags(hints.get_flags() & ~mask);
801 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags()));
802 XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(),
803 window.getWindow(),
804 hints.pData);
805 } finally {
806 XToolkit.awtUnlock();
807 }
808 }
809
810
811
812
813
814
815
816 static int normalizeMotifDecor(int decorations) {
817 if ((decorations & MWMConstants.MWM_DECOR_ALL) == 0) {
818 return decorations;
819 }
820 int d = MWMConstants.MWM_DECOR_BORDER | MWMConstants.MWM_DECOR_RESIZEH
821 | MWMConstants.MWM_DECOR_TITLE
822 | MWMConstants.MWM_DECOR_MENU | MWMConstants.MWM_DECOR_MINIMIZE
823 | MWMConstants.MWM_DECOR_MAXIMIZE;
824 d &= ~decorations;
825 return d;
826 }
827
828
829
830
831
832
833
834 static int normalizeMotifFunc(int functions) {
835 if ((functions & MWMConstants.MWM_FUNC_ALL) == 0) {
836 return functions;
837 }
838 int f = MWMConstants.MWM_FUNC_RESIZE |
839 MWMConstants.MWM_FUNC_MOVE |
840 MWMConstants.MWM_FUNC_MAXIMIZE |
841 MWMConstants.MWM_FUNC_MINIMIZE |
842 MWMConstants.MWM_FUNC_CLOSE;
843 f &= ~functions;
844 return f;
845 }
846
847
848
849
850
851 static void setOLDecor(XWindow window, boolean resizable, int decorations) {
852 if (window == null) {
853 return;
854 }
855
856 XAtomList decorDel = new XAtomList();
857 decorations = normalizeMotifDecor(decorations);
858 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + Integer.toBinaryString(decorations));
859 if ((decorations & MWMConstants.MWM_DECOR_TITLE) == 0) {
860 decorDel.add(XA_OL_DECOR_HEADER);
861 }
862 if ((decorations & (MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE)) == 0) {
863 decorDel.add(XA_OL_DECOR_RESIZE);
864 }
865 if ((decorations & (MWMConstants.MWM_DECOR_MENU |
866 MWMConstants.MWM_DECOR_MAXIMIZE |
867 MWMConstants.MWM_DECOR_MINIMIZE)) == 0)
868 {
869 decorDel.add(XA_OL_DECOR_CLOSE);
870 }
871 if (decorDel.size() == 0) {
872 insLog.finer("Deleting OL_DECOR");
873 XA_OL_DECOR_DEL.DeleteProperty(window);
874 } else {
875 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Setting OL_DECOR to " + decorDel);
876 XA_OL_DECOR_DEL.setAtomListProperty(window, decorDel);
877 }
878 }
879
880
881
882
883 static void setMotifDecor(XWindow window, boolean resizable, int decorations, int functions) {
884
885 if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0
886 && (decorations != MWMConstants.MWM_DECOR_ALL))
887 {
888 decorations = normalizeMotifDecor(decorations);
889 }
890 if ((functions & MWMConstants.MWM_FUNC_ALL) != 0
891 && (functions != MWMConstants.MWM_FUNC_ALL))
892 {
893 functions = normalizeMotifFunc(functions);
894 }
895
896 PropMwmHints hints = window.getMWMHints();
897 hints.set_flags(hints.get_flags() |
898 MWMConstants.MWM_HINTS_FUNCTIONS |
899 MWMConstants.MWM_HINTS_DECORATIONS);
900 hints.set_functions(functions);
901 hints.set_decorations(decorations);
902
903 if (stateLog.isLoggable(PlatformLogger.FINER)) stateLog.finer("Setting MWM_HINTS to " + hints);
904 window.setMWMHints(hints);
905 }
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923 static boolean needRemap(XDecoratedPeer window) {
924
925
926 return !window.isEmbedded();
927 }
928
929
930
931
932
933 static void setShellDecor(XDecoratedPeer window) {
934 int decorations = window.getDecorations();
935 int functions = window.getFunctions();
936 boolean resizable = window.isResizable();
937
938 if (!resizable) {
939 if ((decorations & MWMConstants.MWM_DECOR_ALL) != 0) {
940 decorations |= MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE;
941 } else {
942 decorations &= ~(MWMConstants.MWM_DECOR_RESIZEH | MWMConstants.MWM_DECOR_MAXIMIZE);
943 }
944 }
945 setMotifDecor(window, resizable, decorations, functions);
946 setOLDecor(window, resizable, decorations);
947
948
949 if (window.isShowing() && needRemap(window)) {
950
951
952
953
954
955 window.xSetVisible(false);
956 XToolkit.XSync();
957 window.xSetVisible(true);
958 }
959 }
960
961
962
963
964 static void setShellResizable(XDecoratedPeer window) {
965 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell resizable " + window);
966 XToolkit.awtLock();
967 try {
968 Rectangle shellBounds = window.getShellBounds();
969 shellBounds.translate(-window.currentInsets.left, -window.currentInsets.top);
970 window.updateSizeHints(window.getDimensions());
971 requestWMExtents(window.getWindow());
972 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
973 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
974
975
976
977 removeSizeHints(window, XUtilConstants.PMaxSize);
978 window.updateMinimumSize();
979
980
981 setShellDecor(window);
982 } finally {
983 XToolkit.awtUnlock();
984 }
985 }
986
987
988
989
990
991
992 static void setShellNotResizable(XDecoratedPeer window, WindowDimensions newDimensions, Rectangle shellBounds,
993 boolean justChangeSize)
994 {
995 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting non-resizable shell " + window + ", dimensions " + newDimensions +
996 ", shellBounds " + shellBounds +", just change size: " + justChangeSize);
997 XToolkit.awtLock();
998 try {
999
1000 if (!shellBounds.isEmpty()) {
1001 window.updateSizeHints(newDimensions);
1002 requestWMExtents(window.getWindow());
1003 XToolkit.XSync();
1004 XlibWrapper.XMoveResizeWindow(XToolkit.getDisplay(), window.getShell(),
1005 shellBounds.x, shellBounds.y, shellBounds.width, shellBounds.height);
1006 }
1007 if (!justChangeSize) {
1008 setShellDecor(window);
1009 }
1010 } finally {
1011 XToolkit.awtUnlock();
1012 }
1013 }
1014
1015
1016
1017
1018 private HashMap<Class<?>, Collection<?>> protocolsMap = new HashMap<Class<?>, Collection<?>>();
1019
1020
1021
1022 <T> Collection<T> getProtocols(Class<T> protocolInterface) {
1023 Collection<T> res = (Collection<T>) protocolsMap.get(protocolInterface);
1024 if (res != null) {
1025 return res;
1026 } else {
1027 return new LinkedList<T>();
1028 }
1029 }
1030
1031 private <T> void addProtocol(Class<T> protocolInterface, T protocol) {
1032 Collection<T> protocols = getProtocols(protocolInterface);
1033 protocols.add(protocol);
1034 protocolsMap.put(protocolInterface, protocols);
1035 }
1036
1037 boolean supportsDynamicLayout() {
1038 int wm = getWMID();
1039 switch (wm) {
1040 case XWM.ENLIGHTEN_WM:
1041 case XWM.KDE2_WM:
1042 case XWM.SAWFISH_WM:
1043 case XWM.ICE_WM:
1044 case XWM.METACITY_WM:
1045 return true;
1046 case XWM.OPENLOOK_WM:
1047 case XWM.MOTIF_WM:
1048 case XWM.CDE_WM:
1049 return false;
1050 default:
1051 return false;
1052 }
1053 }
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063 boolean supportsExtendedState(int state) {
1064 switch (state) {
1065 case Frame.MAXIMIZED_VERT:
1066 case Frame.MAXIMIZED_HORIZ:
1067
1068
1069
1070
1071 if (getWMID() == METACITY_WM) {
1072
1073 return false;
1074 }
1075
1076 case Frame.MAXIMIZED_BOTH:
1077 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1078 if (proto.supportsState(state)) {
1079 return true;
1080 }
1081 }
1082 default:
1083 return false;
1084 }
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094 int getExtendedState(XWindowPeer window) {
1095 int state = 0;
1096 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1097 state |= proto.getState(window);
1098 }
1099 if (state != 0) {
1100 return state;
1101 } else {
1102 return Frame.NORMAL;
1103 }
1104 }
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116 boolean isStateChange(XDecoratedPeer window, XPropertyEvent e) {
1117 if (!window.isShowing()) {
1118 stateLog.finer("Window is not showing");
1119 return false;
1120 }
1121
1122 int wm_state = window.getWMState();
1123 if (wm_state == XUtilConstants.WithdrawnState) {
1124 stateLog.finer("WithdrawnState");
1125 return false;
1126 } else {
1127 stateLog.finer("Window WM_STATE is " + wm_state);
1128 }
1129 boolean is_state_change = false;
1130 if (e.get_atom() == XA_WM_STATE.getAtom()) {
1131 is_state_change = true;
1132 }
1133
1134 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1135 is_state_change |= proto.isStateChange(e);
1136 stateLog.finest(proto + ": is state changed = " + is_state_change);
1137 }
1138 return is_state_change;
1139 }
1140
1141
1142
1143
1144 int getState(XDecoratedPeer window) {
1145 int res = 0;
1146 final int wm_state = window.getWMState();
1147 if (wm_state == XUtilConstants.IconicState) {
1148 res = Frame.ICONIFIED;
1149 } else {
1150 res = Frame.NORMAL;
1151 }
1152 res |= getExtendedState(window);
1153 return res;
1154 }
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166 void setLayer(XWindowPeer window, int layer) {
1167 for (XLayerProtocol proto : getProtocols(XLayerProtocol.class)) {
1168 if (proto.supportsLayer(layer)) {
1169 proto.setLayer(window, layer);
1170 }
1171 }
1172 XToolkit.XSync();
1173 }
1174
1175 void setExtendedState(XWindowPeer window, int state) {
1176 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1177 if (proto.supportsState(state)) {
1178 proto.setState(window, state);
1179 break;
1180 }
1181 }
1182
1183 if (!window.isShowing()) {
1184
1185
1186
1187
1188 XToolkit.awtLock();
1189 try {
1190 XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
1191 window.getWindow(),
1192 XA_KWM_WIN_ICONIFIED.getAtom());
1193 XlibWrapper.XDeleteProperty(XToolkit.getDisplay(),
1194 window.getWindow(),
1195 XA_KWM_WIN_MAXIMIZED.getAtom());
1196 }
1197 finally {
1198 XToolkit.awtUnlock();
1199 }
1200 }
1201 XToolkit.XSync();
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219 void unshadeKludge(XDecoratedPeer window) {
1220 assert(window.isShowing());
1221
1222 for (XStateProtocol proto : getProtocols(XStateProtocol.class)) {
1223 proto.unshadeKludge(window);
1224 }
1225 XToolkit.XSync();
1226 }
1227
1228 static boolean inited = false;
1229 static void init() {
1230 if (inited) {
1231 return;
1232 }
1233
1234 initAtoms();
1235 getWM();
1236 inited = true;
1237 }
1238
1239 void initializeProtocols() {
1240 XNETProtocol net_protocol = g_net_protocol;
1241 if (net_protocol != null) {
1242 if (!net_protocol.active()) {
1243 net_protocol = null;
1244 } else {
1245 if (net_protocol.doStateProtocol()) {
1246 addProtocol(XStateProtocol.class, net_protocol);
1247 }
1248 if (net_protocol.doLayerProtocol()) {
1249 addProtocol(XLayerProtocol.class, net_protocol);
1250 }
1251 }
1252 }
1253
1254 XWINProtocol win = g_win_protocol;
1255 if (win != null) {
1256 if (win.active()) {
1257 if (win.doStateProtocol()) {
1258 addProtocol(XStateProtocol.class, win);
1259 }
1260 if (win.doLayerProtocol()) {
1261 addProtocol(XLayerProtocol.class, win);
1262 }
1263 }
1264 }
1265 }
1266
1267 HashMap storedInsets = new HashMap();
1268 Insets guessInsets(XDecoratedPeer window) {
1269 Insets res = (Insets)storedInsets.get(window.getClass());
1270 if (res == null) {
1271 switch (WMID) {
1272 case ENLIGHTEN_WM:
1273 res = new Insets(19, 4, 4, 4);
1274 break;
1275 case CDE_WM:
1276 res = new Insets(28, 6, 6, 6);
1277 break;
1278 case NO_WM:
1279 case LG3D_WM:
1280 res = zeroInsets;
1281 break;
1282 case MOTIF_WM:
1283 case OPENLOOK_WM:
1284 default:
1285 res = defaultInsets;
1286 }
1287 }
1288 if (insLog.isLoggable(PlatformLogger.FINEST)) insLog.finest("WM guessed insets: " + res);
1289 return res;
1290 }
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301 static int awtWMStaticGravity = -1;
1302 static boolean configureGravityBuggy() {
1303
1304 if (awtWMStaticGravity == -1) {
1305 awtWMStaticGravity = (XToolkit.getEnv("_JAVA_AWT_WM_STATIC_GRAVITY") != null) ? 1 : 0;
1306 }
1307
1308 if (awtWMStaticGravity == 1) {
1309 return true;
1310 }
1311
1312 switch(getWMID()) {
1313 case XWM.ICE_WM:
1314
1315
1316
1317
1318
1319
1320
1321
1322 if (g_net_protocol != null) {
1323 String wm_name = g_net_protocol.getWMName();
1324 Pattern pat = Pattern.compile("^IceWM (\\d+)\\.(\\d+)\\.(\\d+).*$");
1325 try {
1326 Matcher match = pat.matcher(wm_name);
1327 if (match.matches()) {
1328 int v1 = Integer.parseInt(match.group(1));
1329 int v2 = Integer.parseInt(match.group(2));
1330 int v3 = Integer.parseInt(match.group(3));
1331 return !(v1 > 1 || (v1 == 1 && (v2 > 2 || (v2 == 2 && v3 >=2))));
1332 }
1333 } catch (Exception e) {
1334 return true;
1335 }
1336 }
1337 return true;
1338 case XWM.ENLIGHTEN_WM:
1339
1340 return true;
1341 default:
1342 return false;
1343 }
1344 }
1345
1346
1347
1348
1349
1350 public static Insets getInsetsFromExtents(long window) {
1351 if (window == XConstants.None) {
1352 return null;
1353 }
1354 XNETProtocol net_protocol = getWM().getNETProtocol();
1355 if (net_protocol != null && net_protocol.active()) {
1356 Insets insets = getInsetsFromProp(window, XA_NET_FRAME_EXTENTS);
1357 insLog.fine("_NET_FRAME_EXTENTS: {0}", insets);
1358
1359 if (insets != null) {
1360 return insets;
1361 }
1362 }
1363 switch(getWMID()) {
1364 case XWM.KDE2_WM:
1365 return getInsetsFromProp(window, XA_KDE_NET_WM_FRAME_STRUT);
1366 case XWM.ENLIGHTEN_WM:
1367 return getInsetsFromProp(window, XA_E_FRAME_SIZE);
1368 default:
1369 return null;
1370 }
1371 }
1372
1373
1374
1375
1376
1377 public static Insets getInsetsFromProp(long window, XAtom atom) {
1378 if (window == XConstants.None) {
1379 return null;
1380 }
1381
1382 WindowPropertyGetter getter =
1383 new WindowPropertyGetter(window, atom,
1384 0, 4, false, XAtom.XA_CARDINAL);
1385 try {
1386 if (getter.execute() != XConstants.Success
1387 || getter.getData() == 0
1388 || getter.getActualType() != XAtom.XA_CARDINAL
1389 || getter.getActualFormat() != 32)
1390 {
1391 return null;
1392 } else {
1393 return new Insets((int)Native.getCard32(getter.getData(), 2),
1394 (int)Native.getCard32(getter.getData(), 0),
1395 (int)Native.getCard32(getter.getData(), 3),
1396 (int)Native.getCard32(getter.getData(), 1));
1397 }
1398 } finally {
1399 getter.dispose();
1400 }
1401 }
1402
1403
1404
1405
1406 public static void requestWMExtents(long window) {
1407 if (window == XConstants.None) {
1408 return;
1409 }
1410
1411 log.fine("Requesting FRAME_EXTENTS");
1412
1413 XClientMessageEvent msg = new XClientMessageEvent();
1414 msg.zero();
1415 msg.set_type(XConstants.ClientMessage);
1416 msg.set_display(XToolkit.getDisplay());
1417 msg.set_window(window);
1418 msg.set_format(32);
1419 XToolkit.awtLock();
1420 try {
1421 XNETProtocol net_protocol = getWM().getNETProtocol();
1422 if (net_protocol != null && net_protocol.active()) {
1423 msg.set_message_type(XA_NET_REQUEST_FRAME_EXTENTS.getAtom());
1424 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
1425 false,
1426 XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
1427 msg.getPData());
1428 }
1429 if (getWMID() == XWM.KDE2_WM) {
1430 msg.set_message_type(XA_KDE_NET_WM_FRAME_STRUT.getAtom());
1431 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(),
1432 false,
1433 XConstants.SubstructureRedirectMask | XConstants.SubstructureNotifyMask,
1434 msg.getPData());
1435 }
1436
1437 } finally {
1438 XToolkit.awtUnlock();
1439 msg.dispose();
1440 }
1441 }
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 boolean syncTopLevelPos(long window, XWindowAttributes attrs) {
1453 int tries = 0;
1454 XToolkit.awtLock();
1455 try {
1456 do {
1457 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), window, attrs.pData);
1458 if (attrs.get_x() != 0 || attrs.get_y() != 0) {
1459 return true;
1460 }
1461 tries++;
1462 XToolkit.XSync();
1463 } while (tries < 50);
1464 }
1465 finally {
1466 XToolkit.awtUnlock();
1467 }
1468 return false;
1469 }
1470
1471 Insets getInsets(XDecoratedPeer win, long window, long parent) {
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497 Insets correctWM = XWM.getInsetsFromExtents(window);
1498 insLog.finer("Got insets from property: {0}", correctWM);
1499
1500 if (correctWM == null) {
1501 correctWM = new Insets(0,0,0,0);
1502
1503 correctWM.top = -1;
1504 correctWM.left = -1;
1505
1506 XWindowAttributes lwinAttr = new XWindowAttributes();
1507 XWindowAttributes pattr = new XWindowAttributes();
1508 try {
1509 switch (XWM.getWMID()) {
1510
1511 case XWM.ENLIGHTEN_WM: {
1512
1513 syncTopLevelPos(parent, lwinAttr);
1514 correctWM.left = lwinAttr.get_x();
1515 correctWM.top = lwinAttr.get_y();
1516
1517
1518
1519
1520
1521
1522 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1523 XlibUtil.getParentWindow(parent),
1524 pattr.pData);
1525 correctWM.right = pattr.get_width() -
1526 (lwinAttr.get_width() + correctWM.left);
1527 correctWM.bottom = pattr.get_height() -
1528 (lwinAttr.get_height() + correctWM.top);
1529
1530 break;
1531 }
1532 case XWM.ICE_WM:
1533 case XWM.KDE2_WM:
1534 case XWM.CDE_WM:
1535 case XWM.MOTIF_WM: {
1536
1537 if (syncTopLevelPos(parent, lwinAttr)) {
1538 correctWM.top = lwinAttr.get_y();
1539 correctWM.left = lwinAttr.get_x();
1540 correctWM.right = correctWM.left;
1541 correctWM.bottom = correctWM.left;
1542 } else {
1543 return null;
1544 }
1545 break;
1546 }
1547 case XWM.SAWFISH_WM:
1548 case XWM.OPENLOOK_WM: {
1549
1550 syncTopLevelPos(window, lwinAttr);
1551 correctWM.top = lwinAttr.get_y();
1552 correctWM.left = lwinAttr.get_x();
1553 correctWM.right = correctWM.left;
1554 correctWM.bottom = correctWM.left;
1555 break;
1556 }
1557 case XWM.OTHER_WM:
1558 default: {
1559 insLog.finest("Getting correct insets for OTHER_WM/default, parent: {0}", parent);
1560 syncTopLevelPos(parent, lwinAttr);
1561 int status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1562 window, lwinAttr.pData);
1563 status = XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1564 parent, pattr.pData);
1565 if (lwinAttr.get_root() == parent) {
1566 insLog.finest("our parent is root so insets should be zero");
1567 correctWM = new Insets(0, 0, 0, 0);
1568 break;
1569 }
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582 if (lwinAttr.get_x() == 0 && lwinAttr.get_y() == 0
1583 && lwinAttr.get_width()+2*lwinAttr.get_border_width() == pattr.get_width()
1584 && lwinAttr.get_height()+2*lwinAttr.get_border_width() == pattr.get_height())
1585 {
1586 insLog.finest("Double reparenting detected, pattr({2})={0}, lwinAttr({3})={1}",
1587 lwinAttr, pattr, parent, window);
1588 lwinAttr.set_x(pattr.get_x());
1589 lwinAttr.set_y(pattr.get_y());
1590 lwinAttr.set_border_width(lwinAttr.get_border_width()+pattr.get_border_width());
1591
1592 final long grand_parent = XlibUtil.getParentWindow(parent);
1593
1594 if (grand_parent == lwinAttr.get_root()) {
1595
1596
1597
1598
1599 return null;
1600 } else {
1601 parent = grand_parent;
1602 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
1603 parent,
1604 pattr.pData);
1605 }
1606 }
1607
1608
1609
1610
1611
1612
1613
1614 insLog.finest("Attrs before calculation: pattr({2})={0}, lwinAttr({3})={1}",
1615 lwinAttr, pattr, parent, window);
1616 correctWM = new Insets(lwinAttr.get_y() + lwinAttr.get_border_width(),
1617 lwinAttr.get_x() + lwinAttr.get_border_width(),
1618 pattr.get_height() - (lwinAttr.get_y() + lwinAttr.get_height() + 2*lwinAttr.get_border_width()),
1619 pattr.get_width() - (lwinAttr.get_x() + lwinAttr.get_width() + 2*lwinAttr.get_border_width()));
1620 break;
1621 }
1622 }
1623 } finally {
1624 lwinAttr.dispose();
1625 pattr.dispose();
1626 }
1627 }
1628 if (storedInsets.get(win.getClass()) == null) {
1629 storedInsets.put(win.getClass(), correctWM);
1630 }
1631 return correctWM;
1632 }
1633 boolean isDesktopWindow( long w ) {
1634 if (g_net_protocol != null) {
1635 XAtomList wtype = XAtom.get("_NET_WM_WINDOW_TYPE").getAtomListPropertyList( w );
1636 return wtype.contains( XAtom.get("_NET_WM_WINDOW_TYPE_DESKTOP") );
1637 } else {
1638 return false;
1639 }
1640 }
1641
1642 public XNETProtocol getNETProtocol() {
1643 return g_net_protocol;
1644 }
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655 public boolean setNetWMIcon(XWindowPeer window, java.util.List<XIconInfo> icons) {
1656 if (g_net_protocol != null && g_net_protocol.active()) {
1657 g_net_protocol.setWMIcons(window, icons);
1658 return getWMID() != ICE_WM;
1659 }
1660 return false;
1661 }
1662 }